/**
   Converts a whefs VFS, taken as input from stdin, into an array of
   binary data for use in C. It also provides routines which set up
   a whefs_fs which uses the the array as backing storage.

   License: Public Domain

   Usage: app VariableName < input.whefs > output.c

   Input to stdin should be a whefs VFS container, but this program
   does not confirm that. If it is not, the generated routine for
   opening the VFS will fail, but the generated array can still be
   used as backing-storage for whefs_mkfs(), provided it is big
   enough.
*/

#include <stdio.h>

static char const * appName = 0;

void usage()
{
    printf("Usage: %s OBJECT_NAME < input.whefs > output.c\n\n", appName );
    puts("Converts a whefs VFS, taken as input from stdin, to a C unsigned char array named OBJECT_NAME "
	 "and a constant enum value named OBJECT_NAME_length containing the length "
	 "of the bytes.");
    puts("It also creates the functions OBJECT_NAME_whefs_open() and OBJECT_NAME_whefs_finalize() "
	 "to open and close a whefs associated with that memory.");
    puts("The input should be a whefs VFS, but this program does not verify that.");
    puts("");
}

void print_code( char const * varname )
{
    printf("/**\nShared object used by %s_whefs_open() and %s_whefs_finalize()\n*/\n",
	   varname, varname );
    printf("static whefs_fs * %s_whefs = 0;\n\n",varname);

    printf("/**\nOpens %s_whefs as a whefs VFS (in read/write mode if readWrite is true)\n"
	   "and returns it (or NULL on error). Subsequent calls return the same object\n"
	   "and ignore the readWrite argument.\n*/\n",
	   varname );
    printf("whefs_fs * %s_whefs_open( bool readWrite )\n{\n",varname);
    printf( "\tif( %s_whefs ) return %s_whefs;\n", varname, varname );
    printf( "\twhio_dev * memdev = readWrite ? whio_dev_for_memmap_rw( %s, sizeof(%s) ) : whio_dev_for_memmap_ro( %s, sizeof(%s) );\n",
	    varname, varname, varname, varname );
    printf( "\tif( memdev ) whefs_openfs_dev( memdev, &%s_whefs, true );\n", varname );
    printf( "\tif( memdev && ! %s_whefs ) memdev->api->finalize(memdev);\n", varname );
    printf( "\treturn %s_whefs;\n", varname );
    puts("}\n");

    printf("/**\nFetches %s_whefs as a whefs VFS, but does not open it if it has not already\n"
	   "been opened.\n*/\n",
	   varname );
    printf("whefs_fs * %s_whefs_get()\n{\n",varname);
    printf( "\treturn %s_whefs;\n", varname );
    puts("}\n");

    printf("/**\nFinalizes %s_whefs. It is safe (a no-op) to call multiple times.\n*/\n",
	   varname );
    printf("void %s_whefs_finalize()\n{\n",varname);
    printf( "\twhefs_fs_finalize( %s_whefs );\n\t%s_whefs = 0;\n", varname, varname );
    puts("}\n");
}

int main( int argc, char const ** argv )
{
    appName = argv[0];
    if( (argc != 2) || (argv[1][0] == '-') )
    {
	usage();
	return 1;
    }
    char const * varname = argv[1];

    printf("/* Generated by %s. Edit at your own risk. */\n", appName );
    puts( "#if ! defined(WHEFS_AMALGAMATION_BUILD)" );
    puts( "/* For amalgamation builds the lib headers do not exist: */" );
    puts( "#include <wh/whefs/whefs.h> /* core whefs library */" );
    puts( "#include <wh/whio/whio_devs.h> /* i/o device factories */" );
    puts( "#endif /* WHEFS_AMALGAMATION_BUILD */\n" );
    printf( "/** Memory block used by %s_whefs_open() and friends. */\n", varname );
    printf( "static unsigned char %s[] = {\n\t", varname);

    enum { bufSize = 1024 * 32 };
    unsigned char buf[bufSize];

    size_t rd = 0;
    size_t i = 0;
    size_t flip = 0;
    size_t size = 0;
    while( 0 != (rd = fread( buf, 1, bufSize, stdin ) ) )
    {
	size += rd;
	for(i = 0; i < rd; ++i )
	{
	    printf( "0x%02x", buf[i] );
	    if( !( (rd < bufSize) && (i == rd-1)) ) putchar(',');
	    if( 16 == ++flip )
	    {
		flip = 0;
		printf("\n\t");
	    }
	    else putchar(' ');
	}
    }
    printf("\n\t}; /* end %s */\n\n", varname );
#if 1
    printf( "enum { /** the length of %s, in bytes */ %s_length = %uUL };\n\n",
	    varname, varname, size);
#endif
    print_code( varname );
    return 0;
}
